#include "ET++.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "TypeMatcher.h"

#include "Class.h"
#include "String.h"
#include "Data.h"
#include "OrdColl.h"
#include "Bitmap.h"
#include "Symbol.h"
#include "System.h"

const char *cMagic= "@!OIO";
const int cContentsSize= 1024;

#include "ascii.xpm3"
SmartBitmap gAsciiIcon(ascii);

#include "file.xpm3"
SmartBitmap gFileIcon(file);

#include "image.xpm3"
SmartBitmap gImageIcon(image);

//---- TypeMatcher -------------------------------------------------------------

NewMetaImpl(TypeMatcher,Object, (TP(type), TS(extension), TS(tag), TB(ascii),
															TP(matchers)));

OrdCollection *TypeMatcher::matchers;
bool TypeMatcher::sorted;

void TypeMatcher::AddMatcher(TypeMatcher *ftm)
{
	if (ftm) {
		if (matchers == 0)
			matchers= new OrdCollection;
		matchers->Add(ftm);
		sorted= FALSE;
	}
}

TypeMatcher::TypeMatcher(const Symbol &t, const char *ext, const char *tg,
														bool ia, int prio)
{
	type= &t;
	ascii= ia;
	priority= prio;
	extension= strsave(ext);
	tag= strsave(tg);
	AddMatcher(this);
}

TypeMatcher::~TypeMatcher()
{
	SafeDelete(extension);
	SafeDelete(tag);
	if (matchers) {
		matchers->RemovePtr(this);
		if (matchers->Size() <= 0)
			SafeDelete(matchers);
	}
}

Bitmap *TypeMatcher::GetBitmap()
{
	if (ascii)
		return gAsciiIcon;
	return gFileIcon;
}

bool TypeMatcher::MatchPathName(Data *data, const char *pathname, int)
{
	char *s= strrchr(pathname, '.');
	if (s) {
		s++;
		if (*s)
			return MatchExtension(data, s);
	}
	return FALSE;
}

bool TypeMatcher::MatchExtension(Data*, const char *ext)
{
	return extension && (*ext == *extension) && (strcmp(ext, extension) == 0);
}

bool TypeMatcher::MatchNameAndContents(Data *data, const char*, const char *buf, int len)
{
	return MatchContents(data, buf, len);
}

bool TypeMatcher::MatchContents(Data*, const char *bp, int len)
{
	if (tag) {
		int taglen= strlen(tag);
		if (len >= taglen && *bp == *tag && strncmp(bp, tag, taglen) == 0)
			return TRUE;
	}
	return FALSE;
}

TypeMatcher *TypeMatcher::MatchByName(Data *data)
{
	if (!sorted) {
		matchers->Sort();
		sorted= TRUE;
	}

	Iter next(matchers);
	register TypeMatcher *m;
	const char *bp= data->FullName();
	int len= strlen(bp);

	while (m= (TypeMatcher*) next())
		if (m->MatchPathName(data, bp, len))
			break;

	return m;
}

TypeMatcher *TypeMatcher::MatchByContents(Data *data)
{
	StreamBuf *sb= data->GetStreamBufForReading();
	if (sb == 0)
		return 0;
	IStream is(sb, 0, TRUE);
	char buf[cContentsSize+1];
		
	int l= is.read(buf, cContentsSize);
	if (l < 0)
		l= 0;
	buf[l]= '\0';

	if (!sorted) {
		matchers->Sort();
		sorted= TRUE;
	}
	Iter next(matchers);
	const char *name= data->FullName();
	register TypeMatcher *m;

	while (m= (TypeMatcher*) next())
		if (m->MatchNameAndContents(data, name, buf, l))
			break;

	return m;
}

int TypeMatcher::Compare(Object *op)
{
	return priority - ((TypeMatcher*)op)->priority;
}

